home *** CD-ROM | disk | FTP | other *** search
- {
- Reply to NEWS about IPX/SPX UNIT FOR PASCAL. on 10-20-94
- ipx - IPX communication protocol primitives.
- }
-
- unit ipx;
-
- interface uses DOS;
-
- type
- MessageStr = String;
- IPX_REGS = Registers;
- Byte4 = array[0..3] of byte;
- NetworkNumber = Byte4;
- NetworkNode = array[0..5] of byte;
-
- ECB = record
- link_address : Pointer;
- event_service_routine : Pointer;
- in_use : byte;
- completion_code : byte;
- socket_number : word;
- ipx_workspace : Byte4;
- driver_workspace : array[0..11] of
- byte;
- immediate_address : NetworkNode;
- fragment_count : word;
- fragment : array [0..1] of
- record
- address :
- pointer;
- length :
- word;
- end;
- end;
-
- IPXHEADER = record
- checksum : word;
- length : word;
- transport_control : byte;
- packet_type : byte;
- dest_network_number : NetworkNumber;
- dest_network_node : NetworkNode;
- dest_network_socket : word;
- source_network_number : NetworkNumber;
- source_network_node : NetworkNode;
- source_network_socket : word;
- end;
-
- { ZeroEcb - store zeros in all ecb fields.
- Pre: e is an ECB.
- Post: e is fully zeroed. }
- procedure ZeroEcb( var e : ECB );
-
- { ZeroHeader - Store zeros in all header fields.
- Pre: h is an IPXHEADER.
- Post: h is fulled zeroed. }
- procedure ZeroHeader( var h : IPXHEADER );
-
- { Get1stConnectionNumber - Return first connection number for user name
- Pre: username is valid Novell user name
- Post: Returns first connection number username is logged on or
- 0 if not logged on. }
- function Get1stConnectionNumber( username : string ) : word;
-
- { GetInternetAddress - Get the network:node address for a connection.
- Pre: connection_number is valid for a logged on user.
- Post: network_number is valid number of network.
- physical_node is valid station node.
- }
- function GetInternetAddress( connection_number : byte;
- var network_number : NetworkNumber; {hi:lo}
- var physical_node : NetworkNode ) : integer;
-
- { IPXSPXNotLoaded - Executed when ipxspx called but not loaded.
- Pre: IPX not loaded.
- Post: Execution aborted. }
- procedure IPXSPXNotLoaded(var NovRegs : Registers);
-
- { IPXInstalled - Determine if IPX is installed on workstation.
- Pre: Either IPX is or is not installed.
- Post: If IPX installed initialize global IPXLocation to IPX
- entry
- point and return TRUE.
- Otherwise initialize global IPXLocation to
- IPXSPXNotLoaded
- entry point and return FALSE. }
- function IPXInstalled : Boolean;
-
- { IPXSPX - Call ipxspx at address in IPXLocation.
- Pre: IPXInstalled has been called.
- IPX is installed and NovRegs assigned IPX or SPX
- function
- and parameter values. Not checking is done.
- Post: IPX or SPX function is called.
- NovRegs assigned by call. }
-
- procedure IPXSPX(var NovRegs:Registers);
- { IPXRelinquishControl - Give ipx momentary control of CPU.
- Pre: IPX loaded.
- Post: IPX execution done. }
-
- procedure IPXRelinquishControl;
-
- { IPXCancelEvent - Cancels pending event associated with ECB.
- Pre: e is valid ECB.
- Post: 00 - Success.
- F9 - ECB cannot be canceled.
- FF - ECB not in use. }
- function IPXCancelEvent( var e : ECB ) : byte;
-
- { IPXDisconnectFromTarget - Notify listening node that communications
- woth
- specified socket are being terminated.
- Pre: number:node:socket are valid.
- Post: Node notified. }
- procedure IPXDisconnectFromTarget( network_number : NetWorkNumber;
- network_node : NetWorkNode;
- network_socket : word );
-
- { IPXScheduleEvent - Schedule processing of ECB after timer ticks.
- Pre: ticks is number of 18.2 per second ticks.
- e is a valid ECB at the time processing occurs.
- Post: e is processed after timer ticks. }
- procedure IPXScheduleEvent( ticks : word; var e : ECB );
-
- { IPXOpenSocket - Open an application socket.
- Pre: socket to use (BBA-7FFF). All assumed short-lived.
- Post: 00 - Success.
- FE - Socket table full.
- FF - Socket already open. }
- function IPXOpenSocket( socket : word ) : byte;
-
- { IPXCloseSocket - Close socket. No harm if already closed.
- Pre: socket to close.
- Post: socket is closed. }
- procedure IPXCloseSocket( socket : word );
-
- { IPXListenForPacket - Submit an ECB for use when packet received. Must
- have ECB available when packet received by IPX.
- Pre: e storage is available when ECB processed by IPX.
- e.socket_number opened.
- e.event_svc-routine valid routine or NULL.
- e.fragment_count normally 2.
- e.fragment[0].address to IPX Header buffer.
- e.fragment[0].length = 30.
- e.fragment[1].address to data area <=546 bytes long.
- e.fragment[1].length = length of data area.
- Post: If socket opened, e is added to pool and return TRUE.
- Otherwise return FALSE. }
- function IPXListenForPacket( var e : ECB ) : Boolean;
-
- { IPXSendPacket - Send packet using given ECB.
- Pre: e storage is available when ECB processed by IPX.
- e.socket_number opened.
- e.event_svc-routine valid routine or NULL.
- e.immediate_address is address of destination
- workstation.
- e.fragment_count normally 2.
- e.fragment[0].address to IPX Header buffer.
- e.fragment[0].length = 30.
- e.fragment[1].address to data area <=546 bytes long.
- e.fragment[1].length = length of data area.
- Post: e.completion_code of: 00 - Message sent.
- FC - Event canceled.
- FD - Bad packet. }
-
- { IPXGetLocalTarget - Get the bridge address (or node if not bridged)
- for
- network:node address.
- Pre: dest_network - network number of workstation.
- dest_node - network node of workstation.
- dest_socket - network socket of workstation.
- Post: bridge_address is routing information used by
- IPXSendPacket.
- Return 00 - Success.
- FA - No path to destination. }
- function IPXGetLocalTarget( var dest_network : NetworkNumber;
- var dest_node : NetworkNode;
- dest_socket : word;
- var bridge_address : NetworkNode ) : byte;
-
- { IPXGetIntervalMarker - Return time marker measured in 18.2/sec ticks.
- Pre: None.
- Post: Return time marker. }
- function IPXGetIntervalMarker : word;
-
- { IPXSend - Send a packet to network:node:socket using send_ecb and
- send_header. send_ecb/send_header should be defined outside
- of
- IPXSend as both may be in use by ipx after IPXSend
- completes,
- releasing any local variables.
- Pre: dest_network - network number of destination.
-
- dest_node - network node of destination.
- dest_socket - socket of destination.
- packet_ptr - pointer to send packet.
- packet_len - length of send packet
- send_ecb - ECB to use for sending.
- send_header - IPXHEADER to use for sending.
- send_socket - socket to use for sending.
- Post: If destination reachable, packet is sent. }
- procedure IPXSend( var dest_network : NetworkNumber;
- var dest_node : NetworkNode;
- dest_socket : word; { hi:lo }
- packet_ptr : Pointer;
- packet_len : integer;
- var send_ecb : ECB;
- var send_header : IPXHEADER;
- send_socket : word );
-
- { IPXReceive - Submit an ECB/header and storage buffer for a received
- message.
- Pre: receive_ecb - ECB allocated for recieving.
- receive_header - IPXHEADER allocated for receiving.
- receive_socket - socket to receive on.
- Post: message - area allocated for received message
- holds data.
- message_size - size of message area in bytes.
- }
- procedure IPXReceive( var receive_ecb : ECB;
- var receive_header : IPXHEADER;
- receive_socket : word;
- message : Pointer;
- message_size : word );
- { IPXReceivedFrame - Returns TRUE if message frame received in ECB.
- Pre: receive_ecb - ECB allocated for recieving.
- Post: Returns TRUE if message frame received in ECB.
- }
- function IPXReceivedFrame( receive_ecb : ECB ) : Boolean;
-
-
- {_______________________________________________________________________
- __}
-
- implementation
- type
- REQUESTBUFFER = record
- dest_network_number : NetWorkNumber;
- dest_network_node : NetworkNode;
- dest_network_socket : word;
- end;
- REPLYBUFFER = record
- node_address : NetworkNode;
- end;
- var IPXLocation : Pointer; { Address of ipx }
-
- { abort - Display message and halt.
- Pre: message is a string. }
- procedure abort( message : string );
- begin
- writeln( message );
- Halt(1);
- end;
-
- {$F+}
- { Get1stConnectionNumber - Return first connection number for user name
- Pre: username is valid Novell user name
- Post: Returns first connection number username is logged on or
- 0 if not logged on. }
- function Get1stConnectionNumber( username : string ) : word;
- var
- NovRegs : Registers;
- Request : record
- len : Word;
- buffer_type : Byte;
- object_type : Word;
- name : string[47];
- end;
- Reply : record
- len : Word;
- number_connections : byte;
- connection_num : array[0..99] of byte;
- end;
- begin
- with Request do begin
- len := 51;
- buffer_type := $15;
- object_type := $0100;
- name := username;
- end;
-
- Reply.len := 101; { Maximum number of user connections }
-
- with NovRegs do begin
- AH := $E3;
- DS := Seg(Request); {DS:SI points to request}
- SI := Ofs(Request);
- ES := Seg(Reply); {ES:DI points to reply}
- DI := Ofs(Reply);
- MsDos(NovRegs);
-
- if (Al <> 0) or (Reply.number_connections = 0)
- then Get1stConnectionNumber := 0
- else Get1stConnectionNumber := Reply.connection_num[0];
- end;
- end;
-
- { GetInternetAddress - Get the network:node address for a connection.
- Pre: connection_number is valid for a logged on user.
- Post: network_number is valid number of network.
- physical_node is valid station node.
- }
- function GetInternetAddress( connection_number : byte;
- var network_number : NetworkNumber; {hi:lo}
- var physical_node : NetworkNode ) : integer;
- var
- NovRegs : Registers;
- Request : record
- len : word;
- buffer_type : byte;
- connection_number : byte;
- end;
- Reply : record
- len : word;
- network_number : NetworkNumber;
- physical_node : NetworkNode;
- server_socket : word;
- end;
- begin
- with Request do begin
- len := 2;
- buffer_type := $13;
- end;
- Request.connection_number := connection_number;
- Reply.len := 12;
- with NovRegs do begin
- AH := $E3;
- DS := Seg(Request); {DS:SI points to request}
- SI := Ofs(Request);
- ES := Seg(Reply); {ES:DI points to reply}
- DI := Ofs(Reply);
- MsDos(NovRegs);
- Ah := 0;
- GetInternetAddress := Ax;
- end;
- network_number := Reply.network_number;
- physical_node := Reply.physical_node;
- end;
-
- { IPXSPXNotLoaded - Executed when ipxspx called but not loaded.
- Pre: IPX not loaded.
- Post: Execution aborted. }
- procedure IPXSPXNotLoaded(var NovRegs : Registers);
- begin
- abort('IPX not loaded');
- end;
-
- { ZeroEcb - store zeros in all ecb fields.
- Pre: e is an ECB.
- Post: e is fully zeroed. }
- procedure ZeroEcb( var e : ECB );
- var i : byte;
- begin
- with e do begin
- link_address := Ptr(0,0);
- event_service_routine := Ptr(0,0);
- in_use := 0;
- completion_code := 0;
- socket_number := 0;
- for i := 0 to 3 do
- ipx_workspace[i] := 0;
- for i := 0 to 11 do
- driver_workspace[i] := 0;
- for i := 0 to 5 do
- immediate_address[i] := 0;
- fragment_count := 0;
- for i := 0 to 1 do begin
- fragment[i].address := Ptr(0,0);
- fragment[i].length := 0;
- end;
- end;
- end;
-
- { ZeroHeader - Store zeros in all header fields.
- Pre: h is an IPXHEADER.
- Post: h is fulled zeroed. }
- procedure ZeroHeader( var h : IPXHEADER );
- var i : byte;
- begin
- with h do begin
- checksum := 0;
- length := 0;
- transport_control := 0;
- packet_type := 0;
- for i := 0 to 3 do
- dest_network_number[i] := 0;
- for i := 0 to 5 do
- dest_network_node[i] := 0;
- dest_network_socket := 0;
- for i := 0 to 3 do
- source_network_number[i] := 0;
- for i := 0 to 5 do
- source_network_node[i] := 0;
- source_network_socket := 0;
- end;
- end;
-
- { IPXInstalled - Determine if IPX is installed on workstation.
- Pre: Either IPX is or is not installed.
- Post: If IPX installed initialize global IPXLocation to IPX
- entry
- point and return TRUE.
- Otherwise initialize global IPXLocation to
- IPXSPXNotLoaded
- entry point and return FALSE. }
- function IPXInstalled : Boolean;
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- AX := $7A00; {func 7Ah of int 2Fh is used to detect IPX}
- Intr($2F,NovRegs);
- if AL = $FF then begin {if AL is FFh then IPX is loaded and
- available}
- IPXInstalled := TRUE;
- IPXLocation := Ptr(ES,DI); {pointer to IPX entry point in ES:DI}
- end
- else begin
- IPXInstalled := FALSE; {no IPX installed}
- IPXLocation := @IPXSPXNotLoaded;
- end;
- end;
- end;
-
- { IPXSPX - Call ipxspx at address in IPXLocation.
- Pre: IPXInstalled has been called.
- IPX is installed and NovRegs assigned IPX or SPX
- function
- and parameter values. Not checking is done.
- Post: IPX or SPX function is called.
- NovRegs assigned by call. }
- procedure IPXSPX(var NovRegs:Registers);
- var Ax_, Bx_, Dx_, Di_, Si_, Es_ : word;
- begin
- with NovRegs do begin { Assign simple variables record field
- values }
- Ax_ := Ax;
- Bx_ := Bx;
- Dx_ := Dx;
- Di_ := Di;
- Si_ := Si;
- Es_ := Es;
- end;
-
- asm { Assembler instructions. }
- mov Ax, Ax_ { Initialize CPU registers.}
- mov Bx, Bx_
- mov Dx, Dx_
- mov Di, Di_
- mov Si, Si_
- mov Es, Es_
-
- push Bp
- call dword ptr IPXLocation { Call IPX via address at
- IPXLocation. }
- pop Bp
- mov Ax_, Ax
- mov Dx_, Dx
- end;
-
- NovRegs.Ax := Ax_; { Return register values to caller }
- NovRegs.Dx := Dx_;
- end;
-
- { IPXRelinquishControl - Give ipx momentary control of CPU.
- Pre: IPX loaded.
- Post: IPX execution done. }
- procedure IPXRelinquishControl;
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- Bx := $0a;
- IPXSPX(NovRegs);
- end
- end;
-
- { IPXCancelEvent - Cancels pending event associated with ECB.
- Pre: e is valid ECB.
- Post: 00 - Success.
- F9 - ECB cannot be canceled.
- FF - ECB not in use. }
- function IPXCancelEvent( var e : ECB ) : byte;
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- Bx := $06;
- ES := Seg(e); {ES:SI points to ecb}
- SI := Ofs(e);
- IPXSPX(NovRegs);
- IPXCancelEvent := AL;
- end
- end;
-
- { IPXDisconnectFromTarget - Notify listening node that communications
- woth
- specified socket are being terminated.
- Pre: number:node:socket are valid.
- Post: Node notified. }
- procedure IPXDisconnectFromTarget( network_number : NetWorkNumber;
- network_node : NetWorkNode;
- network_socket : word );
- var NovRegs : IPX_REGS;
- request_buffer : REQUESTBUFFER;
- begin
- with request_buffer do begin
- dest_network_number := network_number;
- dest_network_node := network_node;
- dest_network_socket := network_socket;
- end;
-
- with NovRegs do begin
- Bx := $0B;
- ES := Seg(request_buffer); {ES:SI points to ecb}
- SI := Ofs(request_buffer);
- IPXSPX(NovRegs);
- end
- end;
-
- { IPXScheduleEvent - Schedule processing of ECB after timer ticks.
- Pre: ticks is number of 18.2 per second ticks.
- e is a valid ECB at the time processing occurs.
- Post: e is processed after timer ticks. }
- procedure IPXScheduleEvent( ticks : word; var e : ECB );
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- Bx := $05;
- Ax := ticks;
- ES := Seg(e);
- SI := Ofs(e);
- IPXSPX(NovRegs);
- end;
- end;
-
- { IPXOpenSocket - Open an application socket.
- Pre: socket to use (BBA-7FFF). All assumed short-lived.
- Post: 00 - Success.
- FE - Socket table full.
- FF - Socket already open. }
- function IPXOpenSocket( socket : word ) : byte;
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- Dx := socket;
- Bx := 0;
- Al := 0;
- IPXSPX(NovRegs);
- Ah := 0;
- IPXOpenSocket := Ax;
- end
- end;
-
- { IPXCloseSocket - Close socket. No harm if already closed.
- Pre: socket to close.
- Post: socket is closed. }
- procedure IPXCloseSocket( socket : word );
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- Dx := socket;
- Bx := $0001;
- IPXSPX(NovRegs);
- end
- end;
-
- { IPXListenForPacket - Submit an ECB for use when packet received. Must
- have ECB available when packet received by IPX.
- Pre: e storage is available when ECB processed by IPX.
- e.socket_number opened.
- e.event_svc-routine valid routine or NULL.
- e.fragment_count normally 2.
- e.fragment[0].address to IPX Header buffer.
- e.fragment[0].length = 30.
- e.fragment[1].address to data area <=546 bytes long.
- e.fragment[1].length = length of data area.
- Post: If socket opened, e is added to pool and return TRUE.
- Otherwise return FALSE. }
- function IPXListenForPacket( var e : ECB ) : Boolean;
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- BX := $0004;
- ES := Seg(e); {ES:SI points to ecb}
- SI := Ofs(e);
- IPXSPX(NovRegs);
- IPXListenForPacket := Al = 00;
- end
- end;
-
- { IPXSendPacket - Send packet using given ECB.
- Pre: e storage is available when ECB processed by IPX.
- e.socket_number opened.
- e.event_svc-routine valid routine or NULL.
- e.immediate_address is address of destination
- workstation.
- e.fragment_count normally 2.
- e.fragment[0].address to IPX Header buffer.
- e.fragment[0].length = 30.
- e.fragment[1].address to data area <=546 bytes long.
- e.fragment[1].length = length of data area.
- Post: e.completion_code of: 00 - Message sent.
- FC - Event canceled.
- FD - Bad packet. }
- procedure IPXSendPacket( var e: ECB );
- var NovRegs : IPX_REGS;
- begin
- with NovRegs do begin
- ES := Seg(e); {ES:SI points to ecb}
- SI := Ofs(e);
- BX := $0003;
- IPXSPX(NovRegs);
- end
- end;
-
- { IPXGetLocalTarget - Get the bridge address (or node if not bridged)
- for
- network:node address.
- Pre: dest_network - network number of workstation.
- dest_node - network node of workstation.
- dest_socket - network socket of workstation.
- Post: bridge_address is routing information used by
- IPXSendPacket.
- Return 00 - Success.
- FA - No path to destination. }
- function IPXGetLocalTarget( var dest_network : NetworkNumber;
- var dest_node : NetworkNode;
- dest_socket : word;
- var bridge_address : NetworkNode ) : byte;
- var
- NovRegs : Registers;
- Request : record
- network_number : NetworkNumber;
- physical_node : NetworkNode;
- socket : word;
- end;
- Reply : record
- local_target : NetworkNode;
- end;
- begin
- with Request do begin
- network_number := dest_network;
- physical_node := dest_node;
- socket := dest_socket;
- end;
- with NovRegs do begin
- Es := Seg(Request);
- Si := Ofs(Request);
- Di := Ofs(Reply);
- Bx := $0002;
- IPXSPX(NovRegs);
- Ah := 0;
- IPXGetLocalTarget := Ax;
- bridge_address := Reply.local_target;
- end
- end;
-
- { IPXGetIntervalMarker - Return time marker measured in 18.2/sec ticks.
- Pre: None.
- Post: Return time marker. }
- function IPXGetIntervalMarker : word;
- var
- NovRegs : Registers;
- begin
- with NovRegs do begin
- Bx := $0008;
- IPXSPX(NovRegs);
- IPXGetIntervalMarker := Ax;
- end
- end;
-
- { IPXSend - Send a packet to network:node:socket using send_ecb and
- send_header. send_ecb/send_header should be defined outside
- of
- IPXSend as both may be in use by ipx after IPXSend
- completes,
- releasing any local variables.
- Pre: dest_network - network number of destination.
- dest_node - network node of destination.
- dest_socket - socket of destination.
- packet_ptr - pointer to send packet.
- packet_len - length of send packet
- send_ecb - ECB to use for sending.
- send_header - IPXHEADER to use for sending.
- send_socket - socket to use for sending.
- Post: If destination reachable, packet is sent. }
- procedure IPXSend( var dest_network : NetworkNumber;
- var dest_node : NetworkNode;
- dest_socket : word; { hi:lo }
- packet_ptr : Pointer;
- packet_len : integer;
- var send_ecb : ECB;
- var send_header : IPXHEADER;
- send_socket : word );
- begin
- ZeroEcb(send_ecb);
- ZeroHeader(send_header);
- send_ecb.socket_number := send_socket; { Socket used for sending }
- if IPXGetLocalTarget( dest_network,
- dest_node,
- dest_socket,
- send_ecb.immediate_address ) = 0
- then begin
- with send_ecb do begin
- fragment_count := 2;
- fragment[0].address := @send_header;
- fragment[0].length := sizeof(IPXHEADER);
- fragment[1].address := packet_ptr;
- fragment[1].length := packet_len;
- end;
- with send_header do begin
- packet_type := 4;
- dest_network_number := dest_network;
- dest_network_node := dest_node;
- dest_network_socket := dest_socket;
- end;
- IPXSendPacket( send_ecb );
- end;
- end;
-
- { IPXReceive - Submit an ECB/header and storage buffer for a received
- message.
- Pre: receive_ecb - ECB allocated for recieving.
- receive_header - IPXHEADER allocated for receiving.
- receive_socket - socket to receive on.
- Post: message - area allocated for received message
- holds data.
- message_size - size of message area in bytes.
- }
- procedure IPXReceive( var receive_ecb : ECB;
- var receive_header : IPXHEADER;
- receive_socket : word;
- message : Pointer;
- message_size : word );
- begin
- ZeroEcb(receive_ecb);
- ZeroHeader(receive_header);
- with receive_ecb do begin
- socket_number := receive_socket; { Socket used for receiving }
- fragment_count := 2;
- fragment[0].address := @receive_header;
- fragment[0].length := sizeof(IPXHEADER);
- fragment[1].address := message;
- fragment[1].length := message_size;
- end;
- if not IPXListenForPacket( receive_ecb ) then
- abort('IPX Error - Failure initializing.');
- IPXRelinquishControl; { Give ipx opportunity to process
- }
- end;
-
- { IPXReceivedFrame - Returns TRUE if message frame received in ECB.
- Pre: receive_ecb - ECB allocated for recieving.
- Post: Returns TRUE if message frame received in ECB.
- }
- function IPXReceivedFrame( receive_ecb : ECB ) : Boolean;
- begin
- IPXReceivedFrame := (receive_ecb.completion_code = 0) and
- (receive_ecb.in_use = 0);
- end;
-
- begin
- end.
-